#include <iostream>

#include "list_of_cuts.h"

// void print_cuts(list_of_cuts * p){
//   std::cout << "Struct max cuts: " << p->number_of_cuts 
// 	    << " Current: " << p->cuts_added << "\n";
//   for(int i = 0; i <p->cuts_added;i++){
//     std::cout << "RHS: " << p->rhs[i] << "\n";
//     std::cout << "NZ: " << p->nz[i] << "\n";
//     std::cout << "(val,idx): ";
//     for(int j = 0; j<p->nz[i];j++){
//       std::cout << "(" << p->cut_val_arrays[i][j] << "," 
// 		<< p->cut_idx_arrays[i][j] << ") ";
//     }
//     std::cout << std::endl;
//   }
// }

void change_idx_all_cuts(list_of_cuts * p, int add){
  if(p != NULL){
    for(int i = 0; i <p->cuts_added;i++){
      for(int j = 0; j<p->nz[i];j++){
	p->cut_idx_arrays[i][j] += add;
      }
    }
  }
}

void print_cuts(list_of_cuts * p){
  if(p != NULL){
    std::cout<<"Struct max cuts: "<< p->number_of_cuts << " Current: " << p->cuts_added <<"\n";
    for(int i = 0; i < p->cuts_added;i++){
      std::cout << "C" << i << ": ";
      for(int j = 0; j<p->nz[i];j++){
	std::cout << (p->cut_idx_arrays[i][j])*p->cut_val_arrays[i][j] << " ";
      }
      std::cout << " <= " << p->rhs[i] << "\t nz: " << p->nz[i] <<  std::endl;
    }
  }
}

list_of_cuts *  init_cut_struct(int num_cuts){
  list_of_cuts * p = new list_of_cuts [1];
  p->number_of_cuts = num_cuts;
  p->rhs = new double [num_cuts];
  p->nz = new int [num_cuts];
  p->cut_idx_arrays = new int* [num_cuts];
  p->cut_val_arrays = new double* [num_cuts];
  p->cuts_added = 0;
  return p;
}

void add_cut_struct(list_of_cuts * l,double rhs,int nz,int * idx_array,double * val_array){
  if(l->cuts_added == l->number_of_cuts){
    //std::cout<<"Allocating more mem\n";
    //re allocating
    int temp_num_cuts = l->number_of_cuts*2;
    double* temp_rhs = new double [temp_num_cuts];
    int * temp_nz = new int [temp_num_cuts];
    int ** temp_cut_idx_arrays = new int* [temp_num_cuts];
    double ** temp_cut_val_arrays = new double* [temp_num_cuts];
    
    //copy
    for(int i = 0; i < l->cuts_added;i++){
      temp_rhs[i]= l->rhs[i];
      temp_nz[i] = l->nz[i];
      temp_cut_idx_arrays[i] = l->cut_idx_arrays[i];
      temp_cut_val_arrays[i] = l->cut_val_arrays[i];
    }
    
    //replace
    l->rhs = temp_rhs;
    l->nz = temp_nz;
    l->cut_idx_arrays = temp_cut_idx_arrays ;
    l->cut_val_arrays = temp_cut_val_arrays ;
    l->number_of_cuts = temp_num_cuts;

  }
  
  l->rhs[l->cuts_added] = rhs;
  l->nz[l->cuts_added] = nz;
  int * copy_idx = new int [nz];
  double * copy_val = new double [nz];
  
  for(int i= 0; i < nz; i++){
    copy_idx[i] = idx_array[i];
    copy_val[i] = val_array[i];
  }

  l->cut_idx_arrays[l->cuts_added] = copy_idx;
  l->cut_val_arrays[l->cuts_added] = copy_val;
  l->cuts_added++;
}

void clear_cuts(list_of_cuts* l){
  if(l != NULL){
    delete[] l->rhs;
    //std::cout << "delete! 1\n";
    delete[] l->nz;
    //std::cout << "Cuts added: " << l->cuts_added <<"\n";
    for(int i = 0; i < l->cuts_added; ++i){
      //std::cout << "i: " << i <<"\n";
      if(l->cut_idx_arrays[i] != NULL)
	delete[] l->cut_idx_arrays[i];
      if(l->cut_val_arrays[i] != NULL)
	delete[] l->cut_val_arrays[i];
    }
    //std::cout << "delete! 3\n";
    delete[]l;
    //std::cout << "end to delete!\n";
    l = NULL;
  }
}
